package com.yingxin.yx.framework.security.matcher.filter;

import com.yingxin.yx.framework.encrpty.rsa.RsaUtil;
import com.yingxin.yx.framework.jwt.JwtConst;
import com.yingxin.yx.framework.jwt.JwtHelper;
import com.yingxin.yx.framework.jwt.JwtPayload;
import com.yingxin.yx.framework.security.exception.NotRefreshTokenException;
import com.yingxin.yx.framework.security.exception.RefreshTokenException;
import com.yingxin.yx.framework.security.user.PrincipalDto;
import com.yingxin.yx.framework.security.userdetails.DefaultUserDetailsService;
import com.yingxin.yx.framework.user.core.IUserSupport;
import com.yingxin.yx.framework.user.dto.PermissionDto;
import com.yingxin.yx.framework.user.dto.UserDto;
import com.yingxin.yx.framework.user.exception.UserAuthException;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * JWT接口请求校验拦截器
 * 请求接口时会进入这里验证Token是否合法和过期
 * @author fanchao
 */

public class JwtAuthenticationTokenFilter extends BasicAuthenticationFilter {

    private DefaultUserDetailsService userDetailsService;

    private IUserSupport userSupport;


    public JwtAuthenticationTokenFilter(
            AuthenticationManager authenticationManager,
            AuthenticationEntryPoint authenticationEntryPoint,
            DefaultUserDetailsService userDetailsService,
            IUserSupport userSupport)
    {
        super(authenticationManager, authenticationEntryPoint);
        this.userSupport = userSupport;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String token = request.getHeader(JwtConst.AUTHORIZATION);
        //header里面为空则从request里面获取
        if (org.apache.commons.lang3.StringUtils.isEmpty(token)) {
            token = request.getParameter(JwtConst.AUTHORIZATION);
        }

        // userId
        JwtPayload payload = JwtHelper.getJwtPayload(token);
        String userId = payload.getSub();

        // 根据userId获取user
        UserDto user = userSupport.getUser(userId);
        if (user == null) {
            throw new UserAuthException();
        }
        // 认证token
        try {
            JwtHelper.verifyAccessToken(user.getJwtPrivateKey(), token);
        } catch (ExpiredJwtException e) {
            userSupport.forceOutUser(userId,user.getIsApp());
            if ("/yxerp/activiti/user/taskQtyStat".equals(request.getRequestURI())) {
                NotRefreshTokenException ex = new NotRefreshTokenException("访问token过期，不刷新token");
                onUnsuccessfulAuthentication(request, response, ex);
                getAuthenticationEntryPoint().commence(request, response, ex);
            } else {
                RefreshTokenException ex = new RefreshTokenException("访问token过期，刷新token");
                onUnsuccessfulAuthentication(request, response, ex);
                getAuthenticationEntryPoint().commence(request, response, ex);
            }
            return;
        }
        /**
        // 校验证书时间 退出登录
        LicenseResult verifyResult = userSupport.checkLicense();
        if(!verifyResult.getResult()){
            NotRefreshTokenException ex = new NotRefreshTokenException("访问token过期，不刷新token");
            onUnsuccessfulAuthentication(request, response, ex);
            getAuthenticationEntryPoint().commence(request, response, ex);
            throw new BizException(verifyResult.getMessage());
        }
        */

        /*
        Set<GrantedAuthority> authorities = new HashSet<>();

        for (String role : user.getRoleSet()) {
            authorities.add(new SimpleGrantedAuthority(role));
        }

        for (String res : user.getResourceSet()) {
            authorities.add(new SimpleGrantedAuthority(res));
        }
        */
        PrincipalDto principal = (PrincipalDto) user;
        if (userSupport.isReloadPermissions(userId)) {
            principal = reloadPermissions(principal.getUserId());
        }

        // 数据库用户信息
        UserDto userInfo = userDetailsService.getUserInfo(userId);
        if (principal.getIsApp().equals("APP")) {
            // 前端token里
            String newPassword = RsaUtil.decryptByPrivateKey(user.getAppPassword().trim());
            String confirmNewPassword = RsaUtil.decryptByPrivateKey(userInfo.getAppPassword().trim());
            if (!newPassword.equals(confirmNewPassword)) {
                throw new UserAuthException("403", "修改密码");
            }
            // 每次请求时验证是否APP禁用
            if (userInfo.getIsAppLogon().equals("0")) {
                throw new UserAuthException("403", "APP禁用");
            }
        } else if (principal.getIsApp().equals("WX")) {
            if (userInfo.getIsAppLogon().equals("0")) {
                throw new UserAuthException("403", "APP禁用");
            }
        }
        principal.buildAuthorities();

        /*
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (String permissionString : principal.getResourceSet()) {
            if (StringUtils.isNotEmpty(permissionString)) {
                authorities.add(new SimpleGrantedAuthority(permissionString));
            }
        }
        principal.setAuthorities(authorities);
        */

        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(principal, userId, principal.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

         /*
        // 获取请求头中JWT的Token
        String tokenHeader = request.getHeader(JwtConfig.tokenHeader);

        if (null != tokenHeader && tokenHeader.startsWith(JwtConfig.tokenPrefix)) {
            try {


                // 截取JWT前缀
                String token = tokenHeader.replace(JwtConfig.tokenPrefix, "");
                // 解析JWT
                Claims claims = Jwts.parser()
                        .setSigningKey(JwtConfig.secret)
                        .parseClaimsJws(token)
                        .getBody();
                // 获取用户名
                String username = claims.getSubject();
                String userId = claims.getId();


                if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(userId)) {
                    // 获取角色
                    List<GrantedAuthority> authorities = new ArrayList<>();
                    String authority = claims.get("authorities").toString();
                    if (!StringUtils.isEmpty(authority)) {
                        List<Map<String, String>> authorityMap = JSONObject.parseObject(authority, List.class);
                        for (Map<String, String> role : authorityMap) {
                            if (!StringUtils.isEmpty(role)) {
                                authorities.add(new SimpleGrantedAuthority(role.get("authority")));
                            }
                        }
                    }
                    //组装参数
                    SelfUserEntity selfUserEntity = new SelfUserEntity();
                    selfUserEntity.setUsername(claims.getSubject());
                    selfUserEntity.setUserId(Long.parseLong(claims.getId()));
                    selfUserEntity.setAuthorities(authorities);
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(selfUserEntity, userId, authorities);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            } catch (ExpiredJwtException e) {
                System.out.println("Token过期");
            } catch (Exception e) {
                System.out.println("Token无效");
            }
        }
       */
        filterChain.doFilter(request, response);
        return;
    }


    public void setUserSupport(IUserSupport userSupport) {
        this.userSupport = userSupport;
    }


    public PrincipalDto reloadPermissions(String userId) throws AuthenticationException {
        List<PermissionDto> permissions = userDetailsService.permissions(userId);
        UserDto user = userSupport.getUser(userId);
        user.addResourceSet(permissions);
        // user.setResourceSet(permissionStringSet);
        userSupport.putUser(user);
        return (PrincipalDto) user;
    }

}